import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import momo.app.multicast.Msg;
import momo.app.multicast.MsgRcvListener;
import momo.app.multicast.MulticastComm;
import momo.app.util.FileOutput;

public class App implements MsgRcvListener
{
	private Log log = LogFactory.getLog(App.class);
	private MulticastComm app;
	private String[] contents = new String[50];
	
	public App()
	{
		setupStringBuffer();
		app = new MulticastComm();
		app.addMsgRcvListener(this);
	}
	
	public App(String id)
	{
		setupStringBuffer();
		app = new MulticastComm(id);
		app.addMsgRcvListener(this);
	}
	
	public void setPort(int commPort, int statusPort)
	{
		this.setCommPort(commPort);
		this.setStatusPort(statusPort);
	}
	
	public void setCommPort(int commPort)
	{
		app.setCommPort(commPort);
	}
	
	public void setStatusPort(int statusPort)
	{
		app.setStatusPort(statusPort);
	}
	
	public void setCost(double cost)
	{
		app.setCost(cost);
	}
	
	public void setCost(String source, double cost)
	{
		app.setUserCost(source, cost);
	}
	
//	public void createProfile()
//	{
//		app.createProfile();
//	}
//	
//	public void startListening()
//	{
//		app.startListening();
//	}
	
	public void connect(String host, int statusPort) throws IOException
	{
		app.connect(host, statusPort);
	}
	
	public void msgReceived(Msg msg)
	{
		StringBuffer buffer = new StringBuffer();
		buffer.append("From: "+msg.getSource()+"\n ** "+msg.getContents() );
//		FileOutput.getInstance().logToFile("api_message.log", buffer.toString());
		System.out.println(buffer.toString());
	}
	
	public void send(String contents)
	{
		//System.out.println("Sending: " + contents);
		app.synchronizedSend(contents);
	}
	
	public void massRandomSend()
	{
		Thread sendThread = new Thread()
		{
			public void run()
			{
				Random rand = new Random();
				while(true)
				{
					try
					{
						
						//sleep( (Math.abs(rand.nextInt()) % 5) * 1000 );
						sleep( 1 * 1000 );
						
						//int noOfMsgToSend = Math.abs(rand.nextInt()) % contents.length;
						int noOfMsgToSend = 1;
						for(int i=0; i<noOfMsgToSend; i++)
							send( contents[Math.abs(rand.nextInt()) % contents.length] );
						
					}catch(InterruptedException ie)
					{
						ie.printStackTrace();
					}
				}
			}
		};
		sendThread.start();
	}
	
	public void testRandomReset()
	{
//		Thread resetThread = new Thread()
//		{
//			public void run()
//			{
//				try
//				{
//					Random rand = new Random();
//					int timeToSleep = (5 + ( Math.abs(rand.nextInt()) % 10 )) * 1000;
//					log.warn("@@@@@@ Time to sleep be4 reset: " + timeToSleep );
//					sleep( timeToSleep );
//					
//					app.reset();
//				}catch(Exception e)
//				{
//					e.printStackTrace();
//				}
//			}
//		};
//		resetThread.start();
	}
	
	public void msgLost(Map<String, Set<Integer>> lostMsg)
	{
		StringBuffer buffer = new StringBuffer();
		buffer.append("<<<<<<<<<- Lost Messages ->>>>>>>>>>>\n");
		Iterator<String> keysIter = lostMsg.keySet().iterator();
		while ( keysIter.hasNext() )
		{
			String sourceId = keysIter.next();
			buffer.append(sourceId+": ");
			
			Iterator<Integer> iterSet = lostMsg.get(sourceId).iterator();
			while ( iterSet.hasNext() )
				buffer.append(iterSet.next()+", ");
			buffer.append("\n");
		}
		FileOutput.getInstance().logToFile("lost_msg.log", buffer.toString());
	}
	
	private void setupStringBuffer()
	{
		contents[0] = "<plugins.Message>\n" + 
					"\t<type>GET_MAP</type>\n" + 
					"\t<sender>asa2</sender>\n" + 
					"\t<content class=\"plugins.GetMapMessageContent\">\n" + 
					"\t\t<vector__clock>{asa2=1337907916}</vector__clock>\n" + 
					"\t</content>\n" + 
					"</plugins.Message>";
		contents[1] = "Yes, there are commas, and no errors";
		contents[2] = "Testing on commas, here, there,";
		contents[3] = ",starts commma, ends comma,";
		contents[4] = "commas, xmas, commas, !! ";
		contents[5] = "Jackson on the move";
		contents[6] = "Shes moving up and down again";
		contents[7] = "Is there anyway to say goodbye to goodbye?";
		contents[8] = "Hmmm... Time for food?";
		contents[9] = "I am hungry!!!";
		contents[10] = "What choices do we have in life?";
		contents[11] = "Its a wonderful day";
		contents[12] = "Movies? Anyone?";
		contents[13] = "Friday the 13th!!";
		contents[14] = "Maybe i should buy toto or 4D";
		contents[15] = "Yes!!! Strike!!!";
		contents[16] = "Loading... Loading...";
		contents[17] = "Dell? MSI? Acer? HP?";
		contents[18] = "Today is Tuesday";
		contents[19] = "Is this the last?";
		contents[20] = "Nope.. its the beginning!";
		contents[21] = "The fastest man is the slowest man in a team";
		contents[22] = "I had a great time on vday =)";
		contents[23] = "It was splendid. I enjoyed alot. Thanks";
		contents[24] = "Why doesnt it reconnect back?";
		contents[25] = "Lost too many messages?";
		contents[26] = "Argh... Debugging time";
		contents[27] = "Moving house. Moving to next Room. Move!!";
		contents[28] = "On the way sir!";
		contents[29] = "No Parking dude";
		contents[30] = "I love to cook but i dun like to wash";
		contents[31] = "Listening to Wang Lee Hom's music";
		contents[32] = "What have i missed?";
		contents[33] = "Now and Forever";
		contents[34] = "Win, Lose or Draw";
		contents[35] = "Wheel of Fortune";
		contents[36] = "Lenova Wins!";
		contents[37] = "Black? Red? Pink? Orange? Brown?";
		contents[38] = "SSD? HDD?";
		contents[39] = "Eclipse vs NetBeans";
		contents[40] = "C? C++? or C#?";
		contents[41] = "Have a break. Have a kit kat!";
		contents[42] = "What is the skin colour of Polar Bears?";
		contents[43] = "Ah MENG!!!";
		contents[44] = "Gosh! No! Pls! Noooooo!!!";
		contents[45] = "Shinryuken!!! You lose!!";
		contents[46] = "Win vs Linux";
		contents[47] = "Mac? i mean computers...";
		contents[48] = "McWings!! Yummy!!";
		contents[49] = "Last quote of the day";
		
	}
	
	private static String getHelp()
	{
		StringBuffer help = new StringBuffer();
		help.append("java App [-options]\n\n");
		help.append("where options include:\n");
		help.append("\t-s connects to network as server\n");
		help.append("\t-c [IP:statusPort] connects to server using stated IP and statusPort\n");
		help.append("\t-p [commPort:statusPort] states the port of Comm and Status\n");
		help.append("\t-u [UID] states the User Identification\n");
		
		return help.toString();
	}
	
	private static void displayError(String cause)
	{
		System.out.println(cause+"\n"+App.getHelp());
		System.exit(0);
	}
	
	public static void main(String args[])
	{
		try
		{
			
			int argsLength = args.length;
			if ( argsLength == 0 )
				System.out.println("Invalid No. of arguments\n"+App.getHelp());
			else
			{
				boolean isServer = false;
				boolean isClient = false;
				boolean hasPort = false;
				boolean hasUserName = false;
				boolean hasCost = false;
				boolean hasUserCost = false;
				
				HashMap<String, Double> userCostMap = new HashMap<String, Double>();
				
				String host = "";
				int hostPort = 0;
				int commPort = 0;
				int statusPort = 0;
				double cost = 0;
				String userName = "";
				App app;
				
				try
				{
					for ( int i=0; i< argsLength; i++ )
					{
						if ( args[i].equals("-s") )
						{
							isServer = true;
						}else if ( args[i].equals("-c") )
						{
							i ++;
							StringTokenizer hostTokens = new StringTokenizer(args[i], ":");
							host = hostTokens.nextToken();
							hostPort = Integer.parseInt(hostTokens.nextToken());
							isClient = true;
						}else if ( args[i].equals("-p") )
						{
							i ++;
							StringTokenizer portTokens = new StringTokenizer(args[i], ":");
							commPort = Integer.parseInt(portTokens.nextToken());
							statusPort = Integer.parseInt(portTokens.nextToken());
							hasPort = true;
						}else if ( args[i].equals("-u") )
						{
							i ++;
							userName = args[i];
							hasUserName = true;
						}else if ( args[i].equals("-x") )
						{
							i ++;
							cost = Double.parseDouble(args[i]);
							hasCost = true;
						}else if ( args[i].equals("-uc") )
						{
							i ++;
							String source = args[i];
							i ++;
							cost = Double.parseDouble(args[i]);
							userCostMap.put(source, cost);
							hasUserCost = true;
						}else
						{
							App.displayError("Invalid Command");
						}
					}//end for
				}catch (Exception e) {
					App.displayError("Invalid Command");
				}
					
				if ( isServer == isClient )
					App.displayError("Invalid Command");
				
				if ( hasUserName )
					app = new App(userName);
				else
					app = new App();
				
				if ( hasPort )
					app.setPort(commPort, statusPort);
				
				if ( hasCost )
					app.setCost(cost);
				
				if ( hasUserCost )
				{
					Iterator<String> sourceIter = userCostMap.keySet().iterator();
					while ( sourceIter.hasNext() )
					{
						String source = sourceIter.next();
						double userCost = userCostMap.get(source);
						app.setCost(source, userCost);
					}
				}
				
//				app.createProfile();
//				app.startListening();
//				
//				if ( isClient )
					app.connect(host, hostPort);
				
				app.massRandomSend();
				app.testRandomReset();
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

}//end of class App
